﻿using BCCommon;
using BCMongoEntity.TMS.Location.Horseman;
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace BCMongoData.TMS.Location.Horseman
{
    public class HorsemanLocationMongoData : IHorsemanLocationMongoData
    {
        private MongoDBCommand<HorsemanLocationEntity> mongoCommand;
        private MongoDBCommand<BsonDocument> geoNaerCommand;

        public HorsemanLocationMongoData(IMongoDBConfiguration mongoDBConfiguration)
        {
            this.mongoCommand = new MongoDBCommand<HorsemanLocationEntity>(mongoDBConfiguration, "HorsemanLocation");
            this.geoNaerCommand = new MongoDBCommand<BsonDocument>(mongoDBConfiguration, "HorsemanLocation");
        }

        public IEnumerable<HorsemanLocationEntity> GetGeoNearLocationsByCoordinate(double[] location, double maxDistance, List<BsonElement> query, List<BsonElement> projections)
        {
            List<BsonElement> elementList = new List<BsonElement>
            {
                new BsonElement("near", BsonValue.Create(new double[] { Math.Round(location[0], 8), Math.Round(location[1], 8) })),
                new BsonElement("distanceField", "dis"),
                new BsonElement("spherical", true),
                new BsonElement("maxDistance", maxDistance * 1000 / 6378137),
                new BsonElement("distanceMultiplier", 6378137)
            };
            if (query != null)
            {
                elementList.Add(new BsonElement("query", BsonValue.Create(new BsonDocument(query))));
            }

            List<BsonDocument> bsonDocument = new List<BsonDocument>
            {
                new BsonDocument { { "$geoNear", new BsonDocument(elementList) } }
            };
            if (projections != null)
            {
                bsonDocument.Add(new BsonDocument { { "$project", new BsonDocument(projections) } });
            }

            var pipelineDefinition = PipelineDefinition<BsonDocument, HorsemanLocationNearEntity>.Create(bsonDocument.ToArray());

            var result = this.geoNaerCommand.Aggregate(pipelineDefinition).GetAwaiter().GetResult();
            return result.ToList();
        }


        public HorsemanLocationEntity Update(HorsemanLocationEntity driver)
        {
            var builder = Builders<HorsemanLocationEntity>.Update.Set(x => x.Latitude, driver.Latitude)
                           .Set(y => y.Longitude, driver.Longitude)
                           .Set(y => y.WorkingStatus, driver.WorkingStatus)
                           .Set(y => y.Name, driver.Name)
                           .Set(y => y.Phone, driver.Phone)
                           .Set(y => y.VehicleNo, driver.VehicleNo)
                           .Set(y => y.DeliveryBoxHeight, driver.DeliveryBoxHeight)
                           .Set(y => y.DeliveryBoxWidth, driver.DeliveryBoxWidth)
                           .Set(y => y.DeliveryBoxLength, driver.DeliveryBoxLength)
                           .Set(y => y.ElectricFenceId, driver.ElectricFenceId)
                           .Set(y => y.DriverPhotoPath, driver.DriverPhotoPath)
                           .Set(y => y.ModifyTime, DateTime.Now)
                           .Set(y => y.Coordinate, new double[] { Math.Round(driver.Longitude, 8), Math.Round(driver.Latitude, 8) })
                           .Set(y => y.CityCode, driver.CityCode)
                           .Set(y => y.CountyCode, driver.CountyCode)
                           .Set(y => y.CreditScore, driver.CreditScore)
                           .Set(y => y.DailyReceivedOrders, driver.DailyReceivedOrders)
                           .Set(y => y.TotalReceivedOrders, driver.TotalReceivedOrders);
            this.mongoCommand.UpdateDocumentAsync(d => d.DriverId == driver.DriverId, builder).GetAwaiter().GetResult();
            return this.mongoCommand.SelectDocumentAsync(s => s.DriverId == driver.DriverId).GetAwaiter().GetResult();
        }

        public Task<HorsemanLocationEntity> GetHorsemanLocationInfo(string vehicleNo)
        {
            return this.mongoCommand.SelectDocumentAsync(p => p.VehicleNo == vehicleNo);
        }
    }
}
